using System;
using System.Collections.Generic;
using System.Text;
using System.Data;

namespace Placid.Core
{
    public class Pivot : IDisposable
    {
        private PSchema _schema;        
        private IPivotSource _dSrc;
        private PTree _tree;

        public Pivot()
        {
            _schema = new PSchema();
            _tree = new PTree(this);
            _dSrc = null;
        }

        public void Update()
        {
            _tree.Build(_schema);
        }

        public PSchema Schema
        {
            get { return _schema; }
        }

        public IPivotSource DSrc
        {
            get { return _dSrc; }
            set { _dSrc = value;
            }
        }

        public DataTable GetResult()
        {
            Dictionary<PTreeNode, DataRow> hNodesStrs = new Dictionary<PTreeNode, DataRow>();
            DataTable dt=null;
            DataRow dr;
            PTreeNode tptn;
            int col;

            if (_tree != null && _tree.HorizLeafs.Count > 0 && _tree.VertLeafs.Count > 0)
            {
                dt = new DataTable();
                object[] o;

                for (int i = 0; i < (_tree.HorizRoot.Depth + _tree.VertLeafs.Count - 1); i++) dt.Columns.Add().Caption="";
                o = new object[dt.Columns.Count - 1];
                for (int i = 0; i < (_tree.VertRoot.Depth - 1); i++) dt.Rows.Add(o);

                _tree.HorizLeafs.Sort();

                foreach (PTreeNode ptn in _tree.HorizLeafs)
                {
                    dr = dt.NewRow();

                    tptn = ptn;
                    while (tptn.Parent != null)
                    {
                        dr[_tree.HorizRoot.Depth - tptn.Depth - 1] = tptn.Value;
                        tptn = tptn.Parent;
                    }

                    dt.Rows.Add(dr);
                    hNodesStrs.Add(ptn, dr);
                }

                col = _tree.HorizRoot.Depth - 1;
                foreach (PTreeNode ptn in _tree.VertLeafs)
                {
                    tptn = ptn;
                    while (tptn.Parent != null)
                    {
                        dt.Rows[_tree.VertRoot.Depth - tptn.Depth - 1][col] = tptn.Value;
                        tptn = tptn.Parent;
                    }

                    foreach (PTreeNode hptn in hNodesStrs.Keys)
                    {
                        dr = hNodesStrs[hptn];
                        dr[col] = _tree.NodeMs.GetNodesMeasure(hptn, ptn).Value;
                    }

                    col++;
                }

                for (int i = 0; i < _tree.HorizRoot.Depth - 1; i++)
                {
                    for (int j = dt.Rows.Count-1; j >= _tree.VertRoot.Depth; j--)
                    {
                        if (dt.Rows[j][i] != null && dt.Rows[j - 1][i] != null && dt.Rows[j][i].ToString() == dt.Rows[j - 1][i].ToString())
                        {
                            if (i==0 || dt.Rows[j][i - 1] == null) dt.Rows[j][i] = null;
                        }
                    }
                }

                for (int j = 0; j< _tree.VertRoot.Depth-1; j++)
                {
                    for (int i = dt.Columns.Count - 1; i > _tree.HorizRoot.Depth - 1; i--)
                    {
                        if (dt.Rows[j][i] != null && dt.Rows[j][i - 1] != null && dt.Rows[j][i].ToString() == dt.Rows[j][i - 1].ToString())
                        {
                            if (j == 0 || dt.Rows[j - 1][i] == null) dt.Rows[j][i] = null;
                        }
                    }
                }
            }

            return dt;

        }

        public static string DataTableToString(DataTable dt)
        {
            string str = "";

            if (dt != null)
            {                
                foreach (DataColumn dc in dt.Columns) str += dc.Caption + "\t";
                
                str += Environment.NewLine;

                foreach (DataRow dr in dt.Rows)
                {
                    foreach (DataColumn dc in dt.Columns)
                    {
                        str += (dr[dc] == null || dr[dc] == DBNull.Value) ? "" : dr[dc].ToString();
                        str += "\t";
                    }

                    str += Environment.NewLine;
                }
            }

            return str;
        }

        public override string ToString()
        {
            return DataTableToString(GetResult());
        }

        #region IDisposable Members

        public void Dispose()
        {
            _schema = null;
            if(_dSrc != null)_dSrc.Dispose();
            if(_tree != null) _tree.Dispose();
        }

        #endregion
    }

    #region interfaces

    

    

    

    

    #endregion    
}
